package com.mes.cloud.utils;

import com.alibaba.fastjson.JSON;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class XmlUtils {
    private static Charset UTF8 = Charset.forName("UTF-8");

    public static Map<String, Object> toMap(String xml) {

        InputStream is = new ByteArrayInputStream(xml.getBytes(XmlUtils.UTF8));
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.parse(is);
            return createMap(document.getDocumentElement());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    private static Map<String, Object> createMap(Node node) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();

        //parse attribute
        if (node.hasAttributes()) {
            NamedNodeMap attributes = node.getAttributes();

            for (int j = 0; j < attributes.getLength(); j++) {
                Node item = attributes.item(j);
                map.put(String.format("@%s", item.getNodeName()), item.getTextContent());
            }
        }

        //parse child elements
        NodeList nodeList = node.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node child = nodeList.item(i);
            if (child.getNodeType() != Node.ELEMENT_NODE) continue;

            String childName = child.getLocalName();
            NodeList tmp = child.getChildNodes();

            //text value "<aa>value</aaa>"
            if (tmp.getLength() == 1 && tmp.item(0).getNodeType() == Node.TEXT_NODE) {
                map.put(childName, tmp.item(0).getNodeValue());
            }

            //genereate child map
            Map<String, Object> childMap = createMap(child);
            if (childMap.size() == 0) continue;

            //map or list ( {} or [] )
            if (map.containsKey(childName)) {
                Object value = map.get(childName);
                if (List.class.isAssignableFrom(value.getClass())) {
                    ((List) value).add(childMap);
                } else if (Map.class.isAssignableFrom(value.getClass())) {
                    List list = new ArrayList<Object>();
                    list.add(value);
                    list.add(childMap);
                    map.put(childName, list);
                } else {
                    throw new RuntimeException("WTF");
                }
            } else {
                map.put(childName, childMap);
            }
        }

        return map;
    }

    private static String toJSONString(String xml) {
        Map<String, Object> map = XmlUtils.toMap(xml);
        return JSON.toJSONString(map);
    }

    public static void main(String[] args) {
        String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><questions><question id=\"1\" title=\"年龄分布\" multiple=\"0\"><memo></memo><options><option id=\"1001\" content=\"18-25\" /><option id=\"1002\" content=\"25-35\" /><option id=\"1003\" content=\"35-50\" /><option id=\"1004\" content=\"50-65\" /></options></question></questions>\n";
        Map<String, Object> map = XmlUtils.toMap(xml);
        System.out.println(map);
        System.out.println();
        System.out.println(XmlUtils.toJSONString(xml));
    }
}
